#include "HelloWorldScene.h"
#include "Mech.h"
#include "SimpleAudioEngine.h"
#include "RandomMech.h"
#include "HeroMech.h"

using namespace cocos2d;
using namespace CocosDenshion;

HelloWorld::HelloWorld() : CCLayer()
{
	_tileMap = NULL;
	_bgLayer = NULL;
	mech = NULL;
	enemyTanks = CCArray::array();
	enemyTanks->retain();
	_explosion = NULL;
	_explosion2 = NULL;
	_gameOver = false;
	_exit = NULL;
}

HelloWorld::~HelloWorld()
{
	CC_SAFE_RELEASE(enemyTanks);
}

CCScene* HelloWorld::scene()
{
    CCScene * scene = NULL;
    do 
    {
        // 'scene' is an autorelease object
        scene = CCScene::create();
        CC_BREAK_IF(! scene);

        // 'layer' is an autorelease object
        HelloWorld *layer = HelloWorld::create();
        CC_BREAK_IF(! layer);

        // add layer as a child to scene
        scene->addChild(layer);
    } while (0);

    // return the scene
    return scene;
}

bool HelloWorld::init()
{
    bool bRet = false;
    do 
    {
        CC_BREAK_IF(! CCLayer::init());

		_tileMap = CCTMXTiledMap::tiledMapWithTMXFile("tanks.tmx");
        this->addChild(_tileMap);
 
		_bgLayer = _tileMap->layerNamed("Background");

		CCPoint spawnTileCoord = ccp(4,4);
		CCPoint spawnPos = this->positionForTileCoord(spawnTileCoord);
		this->setViewpointCenter(spawnPos);

		batchNode = CCSpriteBatchNode::batchNodeWithFile("sprites.png");

		_tileMap->addChild(batchNode);
		CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("sprites.plist");
		
		mech = new HeroMech();
		mech->initWithLayer(this,1,5);
		mech->autorelease();
		mech->setPosition(spawnPos);
		batchNode->addChild(mech);

		this->setTouchEnabled(true);
		this->scheduleUpdate();

		SimpleAudioEngine::sharedEngine()->playBackgroundMusic("8bitDungeonLevel.mp3");
		SimpleAudioEngine::sharedEngine()->preloadEffect("explode.wav");
		SimpleAudioEngine::sharedEngine()->preloadEffect("tank1Shoot.wav");
		SimpleAudioEngine::sharedEngine()->preloadEffect("tank2Shoot.wav");

		int NUM_ENEMY_TANKS = 50;
		for (int i = 0; i < NUM_ENEMY_TANKS; ++i)
		{
			RandomMech* enemy = new RandomMech();
			enemy->initWithLayer(this,2,2);
			enemy->autorelease();

			CCPoint randSpot;
			bool inWall = true;
 
			while (inWall) {            
				randSpot.x = CCRANDOM_0_1() * this->tileMapWidth();
				randSpot.y = CCRANDOM_0_1() * this->tileMapHeight();
				inWall = this->isWallAtPosition(randSpot);
			}
 
			enemy->setPosition(randSpot);
			batchNode->addChild(enemy);
			enemyTanks->addObject(enemy);
		}

		_explosion = CCParticleSystemQuad::particleWithFile("explosion.plist");
		_explosion->stopSystem();
		_tileMap->addChild(_explosion,1);
 
		_explosion2 = CCParticleSystemQuad::particleWithFile("explosion2.plist");
		_explosion2->stopSystem();
		_tileMap->addChild(_explosion2,1);
 
		_exit = CCSprite::spriteWithSpriteFrameName("exit.png");
		CCPoint exitTileCoord = ccp(98, 98);
		CCPoint exitTilePos = this->positionForTileCoord(exitTileCoord);
		_exit->setPosition(exitTilePos);
		batchNode->addChild(_exit);
		
		this->setScale(0.5);

		bRet = true;
    } while (0);

    return bRet;
}

float HelloWorld::tileMapHeight()
{
	return _tileMap->getMapSize().height * _tileMap->getTileSize().height;
}
 
float HelloWorld::tileMapWidth()
{
    return _tileMap->getMapSize().width * _tileMap->getTileSize().width;
}

bool HelloWorld::isValidPosition(CCPoint position)
{
    if (position.x < 0 ||
        position.y < 0 ||
        position.x > this->tileMapWidth() ||
        position.y > this->tileMapHeight()) 
	{
        return false;
    }
	return true;
}
 
bool HelloWorld::isValidTileCoord(CCPoint tileCoord) 
{
    if (tileCoord.x < 0 || 
        tileCoord.y < 0 || 
		tileCoord.x >= _tileMap->getMapSize().width ||
        tileCoord.y >= _tileMap->getMapSize().height) 
	{
        return false;
    }
    return true;
}

CCPoint HelloWorld::tileCoordForPosition(CCPoint position)
{
    if (!this->isValidPosition(position)) return ccp(-1,-1);
	int x = position.x / _tileMap->getTileSize().width;
    int y = (this->tileMapHeight() - position.y) / _tileMap->getTileSize().height;
    return ccp(x, y);
}
 
CCPoint HelloWorld::positionForTileCoord(CCPoint tileCoord)
{
    int x = (tileCoord.x * _tileMap->getTileSize().width) + _tileMap->getTileSize().width/2;
    int y = this->tileMapHeight() - (tileCoord.y * _tileMap->getTileSize().height) - _tileMap->getTileSize().height/2;
    return ccp(x, y);
}

void HelloWorld::setViewpointCenter(CCPoint position)
{
	CCSize winSize = CCDirector::sharedDirector()->getWinSize();
 
	int x = max(position.x, winSize.width / 2 / this->getScale());
    int y = max(position.y, winSize.height / 2 / this->getScale());
    x = min(x, this->tileMapWidth() - winSize.width / 2 / this->getScale());
    y = min(y, this->tileMapHeight() - winSize.height/ 2 / this->getScale());
    CCPoint actualPosition = ccp(x, y);
 
    CCPoint centerOfView = ccp(winSize.width/2, winSize.height/2);
    CCPoint viewPoint = ccpSub(centerOfView, actualPosition);
 
	_tileMap->setPosition(viewPoint);
}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
    CCDirector::sharedDirector()->end();
}

void HelloWorld::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)
{
	CCTouch *touch = (CCTouch *)pTouches->anyObject();
	CCPoint mapLocation = _tileMap->convertTouchToNodeSpace(touch);
 
	//mech->moving = true;
	//mech->moveToward(mapLocation);


}

void HelloWorld::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent)
{
	CCTouch *touch = (CCTouch *)pTouches->anyObject();
	CCPoint mapLocation = _tileMap->convertTouchToNodeSpace(touch);
 
}

void HelloWorld::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{
	if (_gameOver) return;

	CCTouch *touch = (CCTouch *)pTouches->anyObject();
	CCPoint mapLocation = _tileMap->convertTouchToNodeSpace(touch);
 
	mech->moving = true;
	mech->moveToward(mapLocation);
}

void HelloWorld::update(float dt)
{
	if (_gameOver) return;
 
	if (CCRect::CCRectIntersectsRect(_exit->boundingBox(), this->mech->boundingBox()))
	{
		this->endScene(kEndReasonWin);
	}
	
	CCArray* childrenToRemove = CCArray::array();
	CCArray* sprites = this->batchNode->getChildren();

	CCObject* it = NULL;
	CCARRAY_FOREACH(sprites, it)
	{
		CCSprite *sprite = dynamic_cast<CCSprite *>(it);
		if (sprite->getTag() != 0) // bullet     
		{
			if( this->isWallAtPosition(sprite->getPosition()) )
			{
				childrenToRemove->addObject(sprite);
				continue;
			}
			
			if (sprite->getTag() == 1) // hero bullet
			{
				for (int j = enemyTanks->count() - 1; j >= 0; j--)
				{
					RandomMech *enemy = (RandomMech *)enemyTanks->objectAtIndex(j);

					if (CCRect::CCRectIntersectsRect(sprite->boundingBox(), enemy->boundingBox())) 
					{
						childrenToRemove->addObject(sprite);
						enemy->hp--;
						if (enemy->hp <= 0)
						{
							SimpleAudioEngine::sharedEngine()->playEffect("explode3.wav");
							_explosion->setPosition(enemy->getPosition());
							_explosion->resetSystem();
							enemyTanks->removeObject(enemy);
							childrenToRemove->addObject(enemy);
						}
						else
						{
							SimpleAudioEngine::sharedEngine()->playEffect("explode2.wav");
						}
					}
				}
			}
			
			if (sprite->getTag() == 2) // enemy bullet 
			{               
				if (CCRect::CCRectIntersectsRect(sprite->boundingBox(),this->mech->boundingBox()))
				{                    
					childrenToRemove->addObject(sprite);
					this->mech->hp--;
 
					if (this->mech->hp <= 0)
					{
						SimpleAudioEngine::sharedEngine()->playEffect("explode2.wav");
						_explosion->setPosition(this->mech->getPosition());
						_explosion->resetSystem();
						this->endScene(kEndReasonLose);
					}
					else
					{
						_explosion2->setPosition(this->mech->getPosition());
						_explosion2->resetSystem();
						SimpleAudioEngine::sharedEngine()->playEffect("explode1.wav");
					}
				}
			}
		}
	}

	CCObject* jt = NULL;
	CCARRAY_FOREACH(childrenToRemove, jt)
	{
		CCNode *child = dynamic_cast<CCNode *>(jt);
		child->removeFromParentAndCleanup(true);
	}

	this->setViewpointCenter(mech->getPosition());
}

bool HelloWorld::isProp(std::string prop,CCPoint tileCoord,CCTMXLayer *layer)
{
    if (!this->isValidTileCoord(tileCoord)) return false;
    int gid = layer->tileGIDAt(tileCoord);
	CCDictionary * properties = _tileMap->propertiesForGID(gid);
    if (properties == NULL) return false;   
	return (properties->objectForKey(prop) != NULL);
}
 
bool HelloWorld::isPropAtPos(std::string prop,CCPoint position,CCTMXLayer *layer)
{
	CCPoint tileCoord = this->tileCoordForPosition(position);
    return this->isProp(prop,tileCoord,layer);
}
 
bool HelloWorld::isWallAtTileCoord(CCPoint tileCoord)
{
	return this->isProp("Wall",tileCoord,_bgLayer);
}
 
bool HelloWorld::isWallAtPosition(CCPoint position)
{
    CCPoint tileCoord = this->tileCoordForPosition(position);
    if (!this->isValidPosition(tileCoord)) return true;
    return this->isWallAtTileCoord(tileCoord);
}
 
bool HelloWorld::isWallAtRect(CCRect rect)
{
    CCPoint lowerLeft = ccp(rect.origin.x, rect.origin.y);
    CCPoint upperLeft = ccp(rect.origin.x, rect.origin.y+rect.size.height);
    CCPoint lowerRight = ccp(rect.origin.x+rect.size.width, rect.origin.y);
    CCPoint upperRight = ccp(rect.origin.x+rect.size.width, rect.origin.y+rect.size.height);
 
    return (this->isWallAtPosition(lowerLeft) || this->isWallAtPosition(upperLeft) ||
            this->isWallAtPosition(lowerRight) || this->isWallAtPosition(upperRight));
}

void HelloWorld::restartTapped(CCObject *sender)
{
	CCDirector::sharedDirector()->replaceScene(CCTransitionZoomFlipX::transitionWithDuration(0.5,HelloWorld::scene()));
}
 
void HelloWorld::endScene(EndReason endReason)
{
    if(_gameOver) return;
    _gameOver = true;
	
	CCSize winSize = CCDirector::sharedDirector()->getWinSize();
 
    std::string message;
    if (endReason == kEndReasonWin)
	{
        message = "You win!";
    } else if (endReason == kEndReasonLose)
	{
        message = "You lose!";
    }
 
	CCLabelBMFont *label = CCLabelBMFont::labelWithString(message.c_str(),"TanksFont.fnt");
	label->setScale(0.1);
    label->setPosition(ccp(winSize.width/2, winSize.height * 0.7));
	this->addChild(label);
 
    CCLabelBMFont *restartLabel = CCLabelBMFont::labelWithString("Restart","TanksFont.fnt");
 
	CCMenuItemLabel *restartItem = CCMenuItemLabel::itemWithLabel(restartLabel,this,menu_selector(HelloWorld::restartTapped));
	restartItem->setScale(0.1);
	restartItem->setPosition(ccp(winSize.width/2, winSize.height * 0.3));
 
    CCMenu *menu = CCMenu::menuWithItems(restartItem,NULL);
	menu->setPosition(CCPointZero);
	this->addChild(menu);
 
    restartItem->runAction(CCScaleTo::actionWithDuration(0.5,4.0));
    label->runAction(CCScaleTo::actionWithDuration(0.5,4.0));
 
}